#include<net/if.h> 

#include "DOTSdkAPI.h"
#include "DOTSdkCallback.h"
#include "include/dot_callback.h"
#include "include/dot_api.h"
#include "include/dot_error.h"
#include "include/dot_define.h"
#include "hi_appcomm_log.h"

#include "Net.h"
#include "DevManager.h"
#include "ProductManager.h"
#include "app_common.h"
#include "Video.h"
#include "UpgradeRecovery.h"

//是否启动
static char g_bind_loop = 0;
//是否启动了SDK、推流等
static char g_start_sdk = 0;
//是否初始
static char m_nSdkInit = 0;
//是否需要配置wifi
static int m_nConfigWifi = 0;
//发送视频序列号
static int m_nVideoSeq;
//发送音频序列号
static int m_nAudioSeq;
//是否已经播放过配置失败音频文
static char g_has_play_config_fail = 0;
//mac地址
static char dot_mac[32] = { 0 };
//是否在配网过程中再次按了配置
static char g_wifi_config_run = 0;
//分辨
static int m_nImageWidth; 
static int m_nImageHeight;
static int g_doorbell_hd = 0;
//产品型号
static YD_PRODUCT_MODEL_TYPE_E yd_product_model = YD_PRODUCT_MODEL_W5; 

//第一帧视频帧
int m_nFirstKeyFrame;
void SnapImage();

void print_log(const char* file, const char* fun, int line, const char* format,...)
{
    const char* p = strrchr(file, '/');
    const char* filename = p ? p + 1 : file;

    va_list ap;
    char prefix[256];
    char buf[1024];

    snprintf(prefix,sizeof(prefix)-1,"[%s:%s:%d]",filename, fun, line);
    strncpy(buf,prefix, sizeof(prefix) - 1);
    int len = strlen(buf);

    va_start(ap,format);
    vsnprintf(buf+len, sizeof(buf) - len - 1, format, ap);
    va_end(ap);
    printf("%s",buf);
}

YD_PRODUCT_MODEL_TYPE_E DOTGetYDProductModel(void)
{
    return yd_product_model;
}

void *DOTThread(void*args)
{
	SET_THREAD_NAME("DOTThread");
	pthread_detach(pthread_self());

	while (1)
	{
		sleep(5);
		if (g_start_sdk)
			SnapImage();
	}

	pthread_exit(0);
}

void DOTGetMacAddress(char *mac)
{
	strcpy(dot_mac, mac);
}

int GetConfigWifiQrcodeStatus()
{
	return m_nConfigWifi;
}

int GetMmacAddress(const char *ifname, char *mac)
{
	int fd = -1;
	struct ifreq if_hwaddr;

	fd = socket(PF_INET, SOCK_STREAM, 0);
	if (fd < 0) {
		return -1;
	}

	memset(&if_hwaddr, 0, sizeof(if_hwaddr));
	strncpy(if_hwaddr.ifr_name, ifname, sizeof(if_hwaddr.ifr_name));

	int ret = ioctl(fd, SIOCGIFHWADDR, &if_hwaddr);
	if (ret >= 0) {
		unsigned char* hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
		sprintf(mac, "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
			hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
	}

	close(fd);

	return ret;
}

int64_t getNowMs(void)
{
	struct timeval tv;
	gettimeofday(&tv, NULL);
	return tv.tv_sec * (int64_t)1000 + tv.tv_usec / 1000;
}

void DOTSetConfigFailParam(int play)
{
	g_has_play_config_fail = play;
}

int DOTGetConfigFailParam(void)
{
	return g_has_play_config_fail;
}

void DOTSetWifiConfigRun(char config)
{
	g_wifi_config_run = config;
}

char DOTGetWifiConfigRun(void)
{
	return g_wifi_config_run;
}

void SnapImage()
{
#ifdef MINI_APP
        return ;
#endif /* MINI_APP */

	char *imagebuf = NULL;
	int   imagesize = 0;

	if (INIT_OK != m_nSdkInit)
		return;

	VideoGetOpsHandle()->get_snap_pic((unsigned char **)(&imagebuf), (int*)&(imagesize));
	if (NULL != imagebuf)
	{
		DoT_PictureInfo_st pic = {0};
		pic.data = imagebuf;
		pic.data_size = imagesize;
		pic.pic_type = DOT_PICTURE_TYPE_JPG;
		pic.width = 640;
		pic.height = 360;
		OUTPUT_LOG("live thumbnail size is %d.\n", pic.data_size);
		DoT_PushThubmnail(0, &pic);
		free(imagebuf);
	}
	
}

void DOTStartAlarm(DoT_AlarmType_en type, unsigned long long event_time)
{
	if (INIT_OK != m_nSdkInit)
		return;

	OUTPUT_LOG("PushAlarmEvent, type = %d, time = %llu\n", type, event_time);
	DoT_DeviceAlarmInfo_st event;
	memset(&event, 0, sizeof(DoT_DeviceAlarmInfo_st));
	event.alarm_type = type;
	DoT_StartAlarm(0, event_time, &event);
}

void DOTStopAlarm(DoT_AlarmType_en type)
{
	if (INIT_OK != m_nSdkInit)
		return;
	
	OUTPUT_LOG("DOTStopAlarm, type = %d\n", type);
	DoT_StopAlarm(0, type);
}

void DOTStopEveryAlarm(void)
{
	LOGD("\nDOTStopEveryAlarm\n");
	if (INIT_OK != m_nSdkInit)
		return;

	DoT_StopAlarm(0, DOT_ALARM_TAMPER_ALARM);
	DoT_StopAlarm(0, DOT_ALARM_PIR_DETECT);
	DoT_StopAlarm(0, DOT_ALARM_RING);
}

int LowPowerStartSDK(DoT_WakeupReason_en reason)
{
	printf("\nLowPowerStartSDK\n");
	DoT_int32  ret = DOT_EC_SUCCESS;

	if (g_start_sdk)
	{
		OUTPUT_LOG("SDK has been started\n");
		return ret;
	}
	else
	{
		g_start_sdk = 1;
	}

	//低功耗设备唤醒，需要调用DoT_Wakeup函数
	//正常的IPC启动则无需调用
	if (DOT_WAKEUP_NONE != reason)
	{
		OUTPUT_LOG("wakeup reason %d\n", reason);
		DoT_Wakeup(reason);
	}
	else
	{
		DoT_Wakeup(DOT_WAKEUP_NONE);
	}

	//启动SDK service
	ret = DoT_StartService();
	if (ret != DOT_EC_SUCCESS)
	{
		OUTPUT_LOG("start service failed. ec=%d\n",ret);
		return ret;
	}

	return ret;
}

int DOTGetSDKStatus(void)
{
	return g_start_sdk;
}

void *DOTStopSDKThread(void*args)
{
	SET_THREAD_NAME("DOTStopSDKThread");
	pthread_detach(pthread_self());

	printf("dot stop, start\n");
	int err = DoT_StopService();
	usleep(500 * 1000);
	printf("dot stop, err = %d\n", err);
	g_start_sdk = 0;

	pthread_exit(0);
}

int DOTStopSDK(void)
{
	pthread_t DotStopSDKPid;
	int err = pthread_create(&DotStopSDKPid, NULL, &DOTStopSDKThread, NULL);
	if (err != 0) {
		LOGE("pthread_create MobileCountryThread failed!\n");
		return -1;
	}
}

int DOTStartBind(int mode)
{
#ifdef MINI_APP
	return 0;
#endif /* MINI_APP */

    if (!g_start_sdk)
    {
		OUTPUT_LOG("SDK not start\n");
    	m_nConfigWifi = 1;
		return -1;
    }
    else
    {
		printf("StartBind(int mode)\n");
		DoT_int32 ret = DoT_StartDeviceBind(4);
		OUTPUT_LOG("DoT_StartDeviceBind, ret:%d\n",ret);
		m_nConfigWifi = 0;   
		return ret;
    }

    return 0;
}

int DOTStopBind()
{
	DoT_int32 ret = DoT_StopDeviceBind();
	OUTPUT_LOG("DoT_StopDeviceBind, ret:%d\n", ret);
	//g_bind_loop = 0;

    return 0;
}

int Doorbell_video_set_HD(int hd)
{
	uint32_t BitRate;
	RealTimeVideoDataFormat videoinfo;
	VIDEO_STREAM_ATTR_S stNewStreamAttr;
	VIDEO_STREAM_ATTR_S stOldStreamAttr;

	videoinfo.codec = RT_CODEC_H264;
	videoinfo.colorDepth = 24;
	videoinfo.framerate = 15;
	videoinfo.frameInterval = 15 * 2;

	if (hd == 0)
	{
		BitRate = 384; //src:512 256
		videoinfo.width  = 640; //src:1280
		videoinfo.height = 360; //src:720
	}
	else if (hd == 1)
	{
		BitRate = 576; //src:800 512
		videoinfo.width  = 1280; //src:1280
		videoinfo.height = 720; //src:720
	}

	memset(&stNewStreamAttr, 0, sizeof(stNewStreamAttr));
	stNewStreamAttr.bitrate = BitRate;
	stNewStreamAttr.width = videoinfo.width;
	stNewStreamAttr.height = videoinfo.height;
	stNewStreamAttr.framerate = videoinfo.framerate;

	VideoGetOpsHandle()->get_resolution(0, &stOldStreamAttr);
	if (stOldStreamAttr.width != stNewStreamAttr.width)
	{
		int Ret = VideoGetOpsHandle()->set_resolution(0, stNewStreamAttr);
		if (Ret < 0) {
	    		LOGE("VideoSetResolution chn:%d failed\n", 0);
	    		return -1;
		} 
	}

	m_nImageWidth = videoinfo.width;
	m_nImageHeight = videoinfo.height;
}

int Doorbell_video_get_HD(void)
{
	return g_doorbell_hd;
}

void OnMediaData(int pagetype, int sync1, unsigned char* data, unsigned int size, unsigned int timestamp, unsigned long long utcms)
{
	if (!m_nSdkInit)
		return;
		
	int ret = 0;

	if (2 == pagetype)
	{
		DoT_VideoInfo_st packet = {0};
		memset(&packet, 0, sizeof(DoT_VideoInfo_st));
		packet.timestamp = timestamp;
		if (utcms)
		{
			packet.utcms = utcms;
		}
		else
		{
			packet.utcms = getNowMs();
		}
#if 0
	char addr[64] = "/sdcard/play.pcm";
	sprintf(addr, "/sdcard/video/OnMediaData/%llu.h264", time(NULL));
	static FILE *fp = NULL;
	if (fp == NULL) {
		fp = fopen(addr, "wb");
		if (fp == NULL) {
			printf("fopen failed\n");
		}
	}

	if (1) {
		fwrite((unsigned char *)data, 1, (unsigned int)size, fp);
		sync();
	}
#endif
		packet.seq = ++m_nVideoSeq;
		packet.media_type = DOT_VIDEO_TYPE_H264;
		packet.data = data;
		packet.width = m_nImageWidth;
		packet.height = m_nImageHeight;
		packet.data_size = size;
		packet.frame_type = (DoT_VideoFrameType_en)sync1;
		if (sync1)
		{
			packet.frame_type = DOT_VIDEO_FRAME_TYPE_IFRAME;
			if (!m_nFirstKeyFrame)
			{
				m_nFirstKeyFrame = 1;
			}
		}
		else
		{
			packet.frame_type = DOT_VIDEO_FRAME_TYPE_PFRAME;
		}
		ret = DoT_PushVideoData(0, 0, &packet);
		if (ret != 0) 
		{
			m_nFirstKeyFrame = 0;
		}
	}
	else if (1 == pagetype)
	{
		DoT_AudioInfo_st packet = {0};
		memset(&packet, 0, sizeof(DoT_VideoInfo_st));
		packet.timestamp = timestamp;
		if (utcms)
		{
			packet.utcms = utcms;
		}
		else
		{
			packet.utcms = getNowMs();
		}
		packet.seq = ++m_nAudioSeq;
		packet.media_type = DOT_AUDIO_TYPE_G711A;
		packet.channel_num = 1;
		packet.sample_rate = 8000;
		packet.sample_bit = 8;
		packet.data = data;
		packet.data_size = size;
		DoT_PushAudioData(0, 0, &packet);
	}

	if (!m_nFirstKeyFrame) 
	{
		return;
	}
}

int InitSDKParams(DoT_InitParams_st* init_params)
{
	if (init_params)
	{
		char cmei[32] = { 0 };
		char strVerName[64] = {0};
		char *pVesionData = NULL;
		char firewareVersion[64] = { 0 };
		int waitCnt = 0;
		
		memset(init_params, 0, sizeof(DoT_InitParams_st)); 

		init_params->max_channel_num      = 1;
		init_params->streams_per_channel  = 1;
		init_params->buf_size_per_stream  = 2 * 1024 * 1024;
		init_params->device_type          = DOT_DEVICE_TYPE_LOWPOWER_DOORBELL;
		init_params->log_max_line = 1000;
		#if 0
		if (PRODUCT_MODEL_B5 == ProductGetHandle()->ProductModel)
			strcpy(init_params->device_model, "BELL_WJA_HS_B5_W");
		else
			strcpy(init_params->device_model, "BELL_WJA_HS_W5_W");
		#else
		if (yd_product_model == YD_PRODUCT_MODEL_B5)
    		strcpy(init_params->device_model, "BELL_WJA_HS_B5_W");
    	else if (yd_product_model == YD_PRODUCT_MODEL_W5)
    		strcpy(init_params->device_model, "BELL_WJA_HS_W5_W");
    	else if (yd_product_model == YD_PRODUCT_MODEL_B7)
    		strcpy(init_params->device_model, "BELL_WJA_HS_B7_W");
    	else if (yd_product_model == YD_PRODUCT_MODEL_B1)
    		strcpy(init_params->device_model, "BELL_WJA_HS_B1_W");
		#endif
		strcpy(init_params->config_path, SDK_CONFIG_FILE_PATH);
		strcpy(init_params->log_path, "");
		DevGetUuid(cmei);
		strcpy(init_params->serial_number, cmei);

		//获取版本
		DevConfigGetSoftVersion(strVerName, sizeof(strVerName));
		printf("strVerName = %s\n", strVerName);
		pVesionData = strchr(strVerName, 'V');
		if (pVesionData)
		{
			strcpy(firewareVersion, pVesionData + 1);
		}
		else
		{
			strcpy(firewareVersion,"1.01.010");
		}
		strcpy(init_params->fw_version, firewareVersion);
		
		//获取mac地址
#if 0
		while (1)
		{
			if (strlen(dot_mac) > 0) {
				printf("get mac ok!!!\n");
				strcpy(init_params->mac, dot_mac);
				printf("init_params->mac.mac:%s\n", init_params->mac);
				break;
			}
			if (!strlen(dot_mac))			
				GetMmacAddress("wlan0", dot_mac);

			usleep(100 * 1000);
			if (++waitCnt >= 50) { //5s
				printf("get mac failed!!!\n");
				strcpy(init_params->mac, "100000000000");
				break;
			}
		}
#else
		while (1)
		{
			GetMmacAddress("wlan0", dot_mac);
			if (strlen(dot_mac) > 0) {
				LOGW("get mac ok!!!\n");
				strcpy(init_params->mac, dot_mac);
				printf("device_info.mac:%s\n", init_params->mac);
				break;
			}
			usleep(100 * 1000);
			if (++waitCnt >= 50) { //5s
				LOGW("get mac failed!!!\n");
				break;
			}
		}

		if (strlen(dot_mac) == 0)
			strcpy(init_params->mac, "100000000000");
#endif	
		OUTPUT_LOG("mac:%s  ,sn:%s, model:%s, log path:%s, config path:%s,  fw_version:%s\n",
							init_params->mac,
							init_params->serial_number, 
						        init_params->device_model,
						        init_params->log_path, 
						        init_params->config_path,
						        init_params->fw_version);
	}
	return 0;
}

void InitSDKCallback(DoT_CallbackFuncList_st* cb_list)
{
	if (cb_list)
	{
        memset(cb_list, 0, sizeof(DoT_CallbackFuncList_st));
        cb_list->cb_set_device_config = cbSetDevConfig;
        cb_list->cb_get_running_info = cbGetDevRunningInfo;
        cb_list->cb_dev_ctrl = cbControlDevCmd;
        cb_list->cb_audio_play = cbAudioPlayCmd;
        cb_list->cb_ptz_ctrl = cbPTZControl;
        cb_list->cb_server_status = cbServerStatus;
        cb_list->cb_upgrade = cbUpgrade;
        cb_list->cb_bind_status = cbDevBindStatus;		
		cb_list->cb_running_status = cbRunningStatus;
    }

	return;
}

//初始化DeviceCapbility函数
  void InitDeviceCapbility(DoT_DeviceHWCapability_st* hw_capbility, DoT_DeviceSWCapability_st* sw_capbility)
{
    memset(hw_capbility, 0, sizeof(DoT_DeviceHWCapability_st));
    memset(sw_capbility, 0, sizeof(DoT_DeviceSWCapability_st));

    // set hardware capbility
    hw_capbility->hw_support_wifi            = true;
    hw_capbility->hw_support_speaker         = true;
    hw_capbility->hw_support_pir             = true;
    hw_capbility->hw_support_microphone      = true;
    hw_capbility->hw_support_battery         = true;
    hw_capbility->hw_support_night_vision    = true;
    hw_capbility->hw_support_led_indicate    = true;
    hw_capbility->hw_support_tamer_alarm     = true;
    hw_capbility->hw_support_ring	     = true;
      
    //set software capbility
    sw_capbility->sw_support_bi_directional_audiotalk = true;
    sw_capbility->sw_support_video_resolution_modify = true;
    sw_capbility->sw_support_remote_wakeup   = true;
    sw_capbility->sw_support_speaker_volume   = true;
	sw_capbility->sw_support_face_detect = true;
}

int DotSdkInit()
{
#ifdef MINI_APP
	return 0;
#endif /* MINI_APP */

	// 恢复升级自检
	UpgradeRecoverySelfCheck();
	
	char version[64] = {0};

	DoT_GetVersion(version);
    	OUTPUT_LOG("version:%s\n", version);
	if (INIT_OK != m_nSdkInit)
	{	
		printf("\n\nDotSdkInit12345\n\n");
		DoT_int32  ret = DOT_EC_SUCCESS;
    
		DoT_InitParams_st init_params;
        DoT_CallbackFuncList_st callback_list;
        DoT_DeviceHWCapability_st hw_capability;
        DoT_DeviceSWCapability_st sw_capability;

		//初始化SDK Params
		InitSDKParams(&init_params);
		InitSDKCallback(&callback_list);
		DoT_TestSetIPv4v6Mode(0);
   		ret = DoT_Initialize(&init_params, &callback_list);
   		if (ret != DOT_EC_SUCCESS) {
		        OUTPUT_LOG("sdk init failed. ec=%d\n",ret);
		        return ret;
		}
		else
		{
			m_nSdkInit = 1;
		}

#if 1
#ifdef SYSTEM_SAFE_MODE
        DoT_SetLogLevel(DOT_LOG_LEVEL_INFO);
#else
		HI_LOG_LEVEL_E debug_level = HI_LOG_GET_LEVEL();
		if (debug_level == HI_LOG_LEVEL_DEBUG)
		{
			DoT_SetLogLevel(DOT_LOG_LEVEL_DEBUG);
		}
		else if (debug_level == HI_LOG_LEVEL_INFO)
		{
			DoT_SetLogLevel(DOT_LOG_LEVEL_INFO);
		}
		else
		{
			DoT_SetLogLevel(DOT_LOG_LEVEL_NONE);
		}
#endif /* SYSTEM_SAFE_MODE */
#else
		DoT_SetLogLevel(DOT_LOG_LEVEL_DEBUG);
		HI_LOG_Config(1, 1, HI_LOG_LEVEL_DEBUG);
#endif

		//初始化DeviceCapbility
		InitDeviceCapbility(&hw_capability, &sw_capability);
		ret = DoT_InitDeviceCapability(0, &hw_capability, &sw_capability);
		if (ret != DOT_EC_SUCCESS) {
			OUTPUT_LOG("DeviceCapability init failed. ec=%d\n", ret);
			return ret;
		}

		VIDEO_STREAM_ATTR_S pstStreamAttr;
		VideoGetOpsHandle()->get_resolution(0, &pstStreamAttr);
		m_nImageWidth = pstStreamAttr.width;
		m_nImageHeight = pstStreamAttr.height;

		pthread_t DotPid;
		int err = pthread_create(&DotPid, NULL, &DOTThread, NULL);
		if (err != 0) {
			LOGE("pthread_create MobileCountryThread failed!\n");
			return -1;
		}

		while (1)
		{
			if (m_nConfigWifi)
			{
				ret = LowPowerStartSDK(DOT_WAKEUP_NONE);
				if (ret != DOT_EC_SUCCESS)
				{
					OUTPUT_LOG("start service failed. ec=%d\n",ret);
					return ret;
				}
				else
				{
					DOTStartBind(1);
				}
			}
			else
			{
				if (WifiCheckIsConnected())
				{
					ret = LowPowerStartSDK(DOT_WAKEUP_NONE);
					if (ret != DOT_EC_SUCCESS)
					{
						OUTPUT_LOG("start service failed. ec=%d\n",ret);
						return ret;
					}
					break;
				}
			}
			usleep(50 * 1000);
		}
	}

	return 0;
}

